package com.kedll.library.mvp;

import android.util.Log;

import com.kedll.library.adapter.MultiTypeAdapter;
import com.kedll.library.util.CollectionUtils;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;

import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;

/**
 * @author QiQi
 * @date 2017/4/24
 */

public abstract class AbstractRefreshPresenter<T extends RefreshingView> extends BasePresenter<T> {

    protected static final int PER_PAGE_COUNT = 10;
    protected boolean refreshing = false;
    protected boolean loading = false;
    protected FooterItem footerItem = new FooterItem();
    protected EmptyItem emptyItem = new EmptyItem();
    protected ErrorItem errorItem = new ErrorItem();
    protected RxAppCompatActivity rxAppCompatActivity;

    protected int page = 1;

    protected MultiTypeAdapter adapter = new MultiTypeAdapter();

    public AbstractRefreshPresenter(T mView) {
        super(mView);
        initItems();
    }

    protected void initItems() {
        errorItem.setOnClickListener(v -> {
            adapter.notifyItemRemoved(adapter.removeItem(errorItem));
            refreshData();
        });

        emptyItem.setOnClickListener(view -> {
            adapter.notifyItemRemoved(adapter.removeItem(emptyItem));
            refreshData();
        });

        footerItem.setOnClickListener(v -> {
            adapter.notifyItemRemoved(adapter.removeItem(footerItem));
            refreshData();
        });

        adapter.addItem(emptyItem);
    }

    ////////////////////////////////////////////////////////
    // public methods for MainView

    /**
     * 刷新数据
     */
    public void refreshData() {
        if (!refreshing) {
            page = 1;
            refreshing = true;
            if (mView != null) {
                mView.setRefreshing(true);
            }
            footerItem.setState(FooterItem.LOADING);
            loadData(false);
        }
    }

    protected void loadData(boolean loadMore) {
        if (loadMore) {
            loading = false;
        } else {
            refreshing = false;
            int size = adapter.getItemCount();
            adapter.clear();
            adapter.notifyItemRangeRemoved(0, size);
            addHead();
        }
        addSubscription
                (Observable.timer(100, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(aLong -> fetchData(loadMore)));
    }

    /**
     * 在此方法中添加列表头部，如果有需要头部的话
     */
    protected void addHead() {
    }

    /**
     * 在此方法中实现数据的刷新或加载
     *
     * @param isLoadMore true = refresh false = loadMore
     */
    protected abstract void fetchData(boolean isLoadMore);

    public MultiTypeAdapter getAdapter() {
        return adapter;
    }

    public void setRxAppCompatActivity(RxAppCompatActivity rxAppCompatActivity) {
        this.rxAppCompatActivity = rxAppCompatActivity;
    }

    /**
     * 加载更多
     */
    public void loadMoreData() {
        int footerPos = adapter.findPos(footerItem);
        if (!loading &&
                footerPos >= 0 &&
                !footerItem.isNoMore()) {
            if (!footerItem.isLoading()) {
                footerItem.setState(FooterItem.LOADING);
                adapter.notifyItemChanged(footerPos);
            }
            loading = true;
            page++;
            loadData(true);
        }
    }

    public void removeItem(int position) {
        adapter.removeItem(position);
        adapter.notifyItemRemoved(position);
        if (adapter.getItemCount() == 1) {
            adapter.clear();
            adapter.notifyItemRangeRemoved(0, 1);
            adapter.addItem(emptyItem);
            adapter.notifyItemRangeInserted(0, 1);
        }
    }

    protected void parserData(boolean loadMore, List<? extends BaseModel> models) {
        if (mView != null) {
            mView.setRefreshing(false);
        }

        if (loadMore) {
            adapter.removeItem(footerItem);
            adapter.notifyItemRemoved(adapter.getItemCount());
        }

        int resultType;
        int dataSize = CollectionUtils.size(models);
        if (dataSize > 0 && dataSize < PER_PAGE_COUNT) {
            //当请求返回的数据数量大于0 ，但小于请求目标数，则认为已经获取完
            resultType = 2;
        } else if (dataSize == 0) {
            //当请求返回的数量为0，则也认为获取完
            resultType = 1;
        } else {//否则认为还可以获取数据
            resultType = 3;
        }
        retrieveItems(resultType, loadMore, models);
    }

    /**
     * @param resultType 0 = 请求出错 1 = 加载完毕 2 = 加载完毕 3 = 正在加载
     * @param loadMore
     * @param datas
     */
    private void retrieveItems(int resultType, boolean loadMore, List<? extends BaseModel> datas) {
        int currentSize = adapter.getItemCount();
        if (resultType == 0) {
            adapter.addItem(loadMore ? footerItem.setState(FooterItem.ERROR) : errorItem);
            adapter.notifyItemRangeInserted(currentSize, 1);
        } else if (resultType == 1) {
            adapter.addItem(loadMore ? footerItem.setState(FooterItem.NO_MORE) : emptyItem);
            adapter.notifyItemRangeInserted(currentSize, 1);
        } else {
            if (resultType == 2) {
                addDataItems(datas);
                // here depends whether you want to display no more data state
                // if you don't want to display this state when has no more data
                // then just don't add it back,
                // but still need set no more state for footerItem
                adapter.addItem(footerItem.setState(FooterItem.NO_MORE));
                mView.loadMoreFinish(false, false);
            } else {
                addDataItems(datas);
                // pre-display loading state to improve user experience
                adapter.addItem(footerItem.setState(FooterItem.LOADING));
                mView.loadMoreFinish(false, true);
            }
            adapter.notifyItemRangeInserted(currentSize, datas.size() + 1);
        }
    }

    protected  void addDataItems(List<? extends BaseModel> datas) {
        for (BaseModel data : datas) {
            adapter.addItem(data.createItem(adapter));
        }
    }

    protected class HttpErrorListener implements Consumer<Throwable> {

        private final boolean loadMore;

        public HttpErrorListener(boolean loadMore) {
            this.loadMore = loadMore;
        }

        @Override
        public void accept(Throwable throwable) {
            if (mView != null) {
                mView.setRefreshing(false);
            }
            if (loadMore) {
                adapter.removeItem(footerItem);
            } else {
                adapter.clear();
            }
            adapter.notifyDataSetChanged();
            page--;
            if (page < 1) {
                page = 1;
            }
            retrieveItems(0, loadMore, null);
        }
    }

}
